/*
 * @Autor: taobo
 * @Date: 2020-06-12 09:00:15
 * @LastEditTime: 2020-06-12 09:37:28
 */ 
#include <iostream>
using namespace std;

template<class T>
class SmartPtr{
private:
    T* ptr;
    int* use_cnt;
public:
    SmartPtr(T*);//construct
    SmartPtr(const SmartPtr<T>&);//copy construct
    SmartPtr<T>& operator=(const SmartPtr<T>&);
    ~SmartPtr();

    T operator*(){
        return *ptr;
    }
    T* operator->(){
        return ptr;
    }
    T* operator+(int i){
        return ptr+i;
    }
    int operator-(const SmartPtr<T>& p){
        return ptr - p.ptr;
    }
    void decrease(){
        if(--(*use_cnt) == 0){
            delete ptr;
            ptr = nullptr;
            delete use_cnt;
            use_cnt = nullptr;
            //cout <<__FILE__<<" "<<"__LINE__"<<'\n';
        }
        
    }
};
template<class T>
SmartPtr<T>::SmartPtr(T *p){
    cout <<"construct...\n";
    ptr = p;
    try{
        use_cnt = new int(1);
    }catch(...){
        delete ptr;
        ptr = nullptr;
        delete use_cnt;
        use_cnt = nullptr;
    }
}
template<class T>
SmartPtr<T>::SmartPtr(const SmartPtr<T>& p){
    cout<< "copy construct...\n";
    use_cnt = p.use_cnt;
    ptr = p.ptr;
    ++(*use_cnt);
}
template<class T>
SmartPtr<T>& SmartPtr<T>::operator=(const SmartPtr<T>& p){
    cout<<"copy assigned...\n";
    if(p.ptr == ptr) return *this;
    this->decrease();
    ++(*p.use_cnt);
    ptr = p.ptr;
    use_cnt = p.use_cnt;
    return *this;
}
template<class T>
SmartPtr<T>::~SmartPtr(){
    this->decrease();
}

int main()
{
    SmartPtr<int> obj(new int(3));
    {
        SmartPtr<int> obj1(obj);
    }
    {
        SmartPtr<int> obj2(new int);
        obj2 = obj;
    }
    return 0;
}